#include <jni.h>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include <string.h>
#include <tinyalsa/tinyalsa.h>
#include<android/log.h>

#define TAG "Nelson"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)

//usb_audio_recorder /data/test.pcm -D 3 -d 0 -c 1 -r 96000

struct pcm *pcm;
enum pcm_format format = PCM_FORMAT_S16_LE;
jobject pcmDataObject;
jfieldID lengthFiled;
jfieldID bufferFiled;

extern "C"
JNIEXPORT jint JNICALL
Java_com_vsoontech_audiorecorder_NativeAudioRecorder_initAudioRecorder(JNIEnv *env, jclass clazz) {

    struct pcm_config config;
    jclass pcmClass = env->FindClass("com/vsoontech/audiorecorder/PcmData");
    // 得到构造方法ID
    jmethodID pcmClassConstructor = env->GetMethodID(pcmClass, "<init>", "()V");

    // 创建Date对象
    jobject pcmObject = env->NewObject(pcmClass, pcmClassConstructor);

    // 创建一个局部引用
    pcmDataObject = env->NewGlobalRef(pcmObject);

    lengthFiled = env->GetFieldID(pcmClass, "length", "I");
    bufferFiled = env->GetFieldID(pcmClass, "buffer", "[B");

    config.channels = 1;
    config.rate = 96000;
    config.period_size = 4096;
    config.period_count = 2;
    config.format = format;
    config.start_threshold = 0;
    config.stop_threshold = 0;
    config.silence_threshold = 0;

    pcm = pcm_open(3, 0, PCM_IN, &config);
    if (!pcm || !pcm_is_ready(pcm)) {
        LOGI("Unable to open PCM device (%s)\n",
             pcm_get_error(pcm));

        return 0;
    }
    return 1;
}

extern "C"
JNIEXPORT jbyteArray JNICALL
Java_com_vsoontech_audiorecorder_NativeAudioRecorder_read(JNIEnv *env, jclass clazz) {

    unsigned int size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));

    char *buffer = static_cast<char *>(malloc(size));

    if (!buffer) {
        LOGI("Unable to allocate %d bytes\n", size);
        free(buffer);
        pcm_close(pcm);
        return NULL;
    }

    LOGI("Capturing sample: %u ch, %u hz, %u bit Size %d \n",
         1,
         9600,
         pcm_format_to_bits(format),
         size);

    int length = pcm_read(pcm, buffer, size);

    LOGI("Length : %d", length);

    jbyteArray audioData = env->NewByteArray(size);
    env->SetByteArrayRegion(audioData, 0, size, reinterpret_cast<const jbyte *>(buffer));

    free(buffer);

    return audioData;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_vsoontech_audiorecorder_NativeAudioRecorder_releaseAudioRecorder(JNIEnv *env,
                                                                          jclass clazz) {
    pcm_close(pcm);
}

extern "C"
JNIEXPORT jobject JNICALL
Java_com_vsoontech_audiorecorder_NativeAudioRecorder_readPcmData(JNIEnv *env, jclass clazz) {
    unsigned int size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));

    char *buffer = static_cast<char *>(malloc(size));

    if (!buffer) {
        LOGI("Unable to allocate %d bytes\n", size);
        free(buffer);
        pcm_close(pcm);
        return NULL;
    }

    LOGI("Capturing sample: %u ch, %u hz, %u bit Size %d \n",
         1,
         9600,
         pcm_format_to_bits(format),
         size);

    int length = pcm_read(pcm, buffer, size);

    LOGI("Length : %d", length);

    jbyteArray audioData = env->NewByteArray(size);
    env->SetByteArrayRegion(audioData, 0, size, reinterpret_cast<const jbyte *>(buffer));

    env->SetObjectField(pcmDataObject, bufferFiled, audioData);
    env->SetIntField(pcmDataObject,lengthFiled,length);

    free(buffer);

    return pcmDataObject;
}